package com.ddxz.csms.service.impl;

import com.ddxz.csms.entity.*;
import com.ddxz.csms.mapper.base.BaseInfoMapper;
import com.ddxz.csms.mapper.run.DataMapper;
import com.ddxz.csms.service.DataService;
import com.ddxz.tool.web.common.ConstData;
import com.ddxz.tool.web.dto.DdxzResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * description
 *
 * @author 朱宗刚
 * @version 1.0.0
 * @date 2021/11/20
 */

@Service
public class DataServiceImpl implements DataService {
    /**
     * 生成beginDate和endDate直接的运行态势数据
     *
     * @param startDate 开始日期：yyyy-MM-dd格式
     * @param endDate   结束日期：yyyy-MM-dd格式
     * @return 生成的数据汇总情况
     */
    @Override
    public DdxzResponse begin(String startDate, String endDate) throws ParseException {
        List<DeviceEntity> deviceList = baseMapper.getAllDevice();
        List<RouteEntity> routeList = baseMapper.getAllRoute();
        List<RuleEntity> ruleList = baseMapper.getAllRule();
        Date start = new SimpleDateFormat("yyyy-MM-dd").parse(startDate);
        Date stop = new SimpleDateFormat("yyyy-MM-dd").parse(endDate);
        Calendar begin = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        begin.setTimeInMillis(start.getTime());
        end.setTimeInMillis(stop.getTime() + 86400000L);

//        generateRuleData(ruleList, begin, end);
//        generateCollectorEventData(deviceList, begin, end);
//        generateCollectorFlowData(deviceList, begin, end);
//        generateDomainAnalyzeData(deviceList, begin, end);
        generateDomainAccessData(deviceList, begin, end);
//        generateClientVisitData(deviceList, begin, end);
//        generateRouteData(routeList, begin, end);
//        generateSourcePortData(routeList, begin, end);
//        generateTargetPortData(routeList, begin, end);
//        generateIpData(routeList, begin, end);
//        generateAreaData(routeList, begin, end);
//        generateRequestData(deviceList, begin, end);
//        generateResponseData(deviceList, begin, end);
        return DdxzResponse.correct(ConstData.OK_MESSAGE);
    }

    private void generateRuleData(List<RuleEntity> ruleList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunRuleEventEntity entity = new RunRuleEventEntity();
        dataMapper.deleteRuleEvent();
        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for (RuleEntity re : ruleList) {
                entity.setRuleId(re.getId());
                entity.setEvents(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                dataMapper.saveRuleEvent(entity);
            }

            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateCollectorEventData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        RunCollectorEventEntity entity = new RunCollectorEventEntity();
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());

        dataMapper.deleteCollectorEvent();
        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for (DeviceEntity de : deviceList) {
                entity.setEvents(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                entity.setIp(getIpLong(de.getDeviceIp()));
                dataMapper.saveCollectorEvent(entity);
            }

            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateCollectorFlowData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunCollectorFlowEntity entity = new RunCollectorFlowEntity();
        dataMapper.deleteCollectorFlow();
        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            tmp.add(Calendar.HOUR, 1);
            for (DeviceEntity de : deviceList) {
                entity.setIp(getIpLong(de.getDeviceIp()));
                entity.setBps(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                dataMapper.saveCollectorFlow(entity);
            }
        }
    }

    private void generateDomainAnalyzeData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunDomainAnalyzeEntity entity = new RunDomainAnalyzeEntity();
        dataMapper.deleteDomainAnalyze();
        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for(DeviceEntity de : deviceList) {
                entity.setNodeIp(getIpLong(de.getDeviceIp()));
                entity.setCsIp(getIpLong(de.getDeviceIp()));
                entity.setDir((long)random.nextInt(6));
                entity.setCount(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                dataMapper.saveDomainAnalyze(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateDomainAccessData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunDomainAccessEntity entity = new RunDomainAccessEntity();
        dataMapper.deleteDomainAccess();
        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for(DeviceEntity de : deviceList) {
                entity.setNodeIp(getIpLong(de.getDeviceIp()));
                entity.setName(DOMAIN_NAME[random.nextInt(DOMAIN_NAME.length)]);
                entity.setCount(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                dataMapper.saveDomainAccess(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateClientVisitData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunClientVisitEntity entity = new RunClientVisitEntity();
        dataMapper.deleteClientVisit();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for(DeviceEntity de: deviceList) {
                entity.setNodeIp(getIpLong(de.getDeviceIp()));
                entity.setClientIp((random.nextInt() + 16843009L) % Integer.MAX_VALUE);
                entity.setCount(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                dataMapper.saveClientVisit(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateRouteData(List<RouteEntity> routeList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunRouteEntity entity = new RunRouteEntity();
        dataMapper.deleteRoute();
        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for (RouteEntity re : routeList) {
                entity.setRouteId(re.getId());
                entity.setProtocol((long) random.nextInt(141) + 1);
                entity.setCount(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                entity.setSize(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                dataMapper.saveRoute(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateSourcePortData(List<RouteEntity> routeList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunSourcePortEntity entity = new RunSourcePortEntity();
        dataMapper.deleteSourcePort();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for (RouteEntity re : routeList) {
                entity.setPort(PORT_APPLICATION[random.nextInt(PORT_APPLICATION.length)]);
                entity.setProtocol((long) random.nextInt(141) + 1);
                entity.setRouteId(re.getId());
                entity.setCount(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                dataMapper.saveSourcePort(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateTargetPortData(List<RouteEntity> routeList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunTargetPortEntity entity = new RunTargetPortEntity();
        dataMapper.deleteTargetPort();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for (RouteEntity re : routeList) {
                entity.setPort(PORT_APPLICATION[random.nextInt(PORT_APPLICATION.length)]);
                entity.setProtocol((long) random.nextInt(141) + 1);
                entity.setRouteId(re.getId());
                entity.setCount(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                dataMapper.saveTargetPort(entity);
            }

            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateIpData(List<RouteEntity> routeList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunIpEntity entity = new RunIpEntity();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for(RouteEntity re : routeList) {
                entity.setRouteId(re.getId());
                entity.setDstCount(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                entity.setSrcCount(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                dataMapper.saveIp(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateAreaData(List<RouteEntity> routeList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunAreaEntity entity = new RunAreaEntity();
        dataMapper.deleteArea();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for (RouteEntity re : routeList) {
                entity.setCid(Math.abs(random.nextLong()) % Integer.MAX_VALUE);
                entity.setRouteId(re.getId());
                entity.setInByte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % 10737418240L);
                entity.setOutByte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % 10737418240L);
                entity.setInPackage(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));
                entity.setOutPackage(Math.abs(Math.round(random.nextGaussian() * 1000) + 10000L));

                dataMapper.saveArea(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateRequestData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunRequestEntity entity = new RunRequestEntity();
        dataMapper.deleteRequest();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for(DeviceEntity de : deviceList) {
                entity.setNodeIp(getIpLong(de.getDeviceIp()));
                entity.setCsIp(getIpLong(de.getDeviceIp()));
                entity.setDir((long)random.nextInt(6));
                entity.setL0Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL64Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL128Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL256Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL512Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL1024Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL1518Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                dataMapper.saveRequest(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private void generateResponseData(List<DeviceEntity> deviceList, Calendar start, Calendar end) {
        Calendar tmp = Calendar.getInstance();
        tmp.setTimeInMillis(start.getTimeInMillis());
        RunResponseEntity entity = new RunResponseEntity();
        dataMapper.deleteResponse();

        while (tmp.before(end)) {
            LOGGER.debug("{}", tmp.getTime());
            entity.setTime(new Timestamp(tmp.getTimeInMillis() + random.nextInt(3600000)));
            for(DeviceEntity de : deviceList) {
                entity.setNodeIp(getIpLong(de.getDeviceIp()));
                entity.setCsIp(getIpLong(de.getDeviceIp()));
                entity.setDir((long)random.nextInt(6));
                entity.setL0Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL64Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL128Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL256Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL512Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL1024Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                entity.setL1518Byte(Math.abs(Math.round(random.nextGaussian() * 1024 * 1024 * 1024) + 4294967296L) % (10*1024*1024*1024));
                dataMapper.saveResponse(entity);
            }
            tmp.add(Calendar.HOUR, 1);
        }
    }

    private Long getIpLong(String ip) {
        String[] arr = ip.split("\\.");
        if (arr.length != 4) {
            LOGGER.error("非法的IP地址: {}", ip);
            return -1L;
        }

        long ipNum = 0;
        for (int i = 3; i >= 0; --i) {
            long tmp = Optional.of(Long.parseLong(arr[3-i])).orElse(-1L);
            if (tmp == -1L) {
                return tmp;
            }
            ipNum |= tmp << (i * 8);
        }

        return ipNum;
    }

    private final BaseInfoMapper baseMapper;
    
    private final static Long[] PORT_APPLICATION = new Long[]{ 1L,        1719L,        5L,        1720L,
        7L,        1758L,        9L,        1759L,        11L,        1789L,        13L,        1812L,        15L,
        1813L,        17L,        1911L,        18L,        1985L,        19L,        1986L,        20L,        1997L,
        21L,        2003L,        22L,        2049L,        23L,        2053L,        25L,        2100L,        37L,
        2102L,        39L,        2103L,        42L,        2104L,        43L,        2105L,        49L,        2150L,
        50L,        2181L,        53L,        2401L,        63L,        2430L,        67L,        2431L,        68L,
        2432L,        69L,        2433L,        70L,        2600L,        71L,        2601L,        72L,        2602L,
        73L,        2603L,        79L,        2604L,        80L,        2605L,        88L,        2606L,        95L,
        2809L,        98L,        2888L,        101L,        2988L,        102L,        3128L,        105L,        3130L,
        106L,        3306L,        107L,        3346L,        109L,        3389L,        110L,        3455L,        111L,
        3888L,        113L,        4000L,        115L,        4011L,        117L,        4040L,        119L,        4321L,
        123L,        4444L,        137L,        4557L,        138L,        4559L,        139L,        5000L,        143L,
        5002L,        161L,        5232L,        162L,        5236L,        163L,        5308L,        164L,        5354L,
        174L,        5355L,        177L,        5432L,        178L,        5601L,        179L,        5680L,        191L,
        5999L,        194L,        6000L,        199L,        6010L,        201L,        6066L,        202L,        6123L,
        204L,        6379L,        206L,        6667L,        209L,        7000L,        210L,        7001L,        213L,
        7002L,        220L,        7003L,        245L,        7004L,        347L,        7005L,        363L,        7006L,
        369L,        7007L,        370L,        7008L,        372L,        7009L,        389L,        7051L,        427L,
        7077L,        434L,        7100L,        435L,        7666L,        443L,        8008L,        444L,        8019L,
        445L,        8020L,        464L,        8030L,        465L,        8031L,        468L,        8032L,        487L,
        8033L,        488L,        8044L,        496L,        8045L,        500L,        8046L,        512L,        8047L,
        513L,        8048L,        514L,        8049L,        515L,        8051L,        517L,        8080L,        518L,
        8081L,        519L,        8088L,        520L,        8089L,        521L,        8090L,        525L,        8091L,
        526L,        8443L,        530L,        8480L,        531L,        8481L,        532L,        8485L,        533L,
        8788L,        535L,        8888L,        538L,        9080L,        540L,        9083L,        543L,        9090L,
        544L,        9092L,        546L,        9100L,        547L,        9200L,        548L,        9300L,        554L,
        9359L,        556L,        9876L,        563L,        10000L,        565L,        10020L,        587L,        10080L,
        610L,        10081L,        611L,        10082L,        612L,        10083L,        616L,        11000L,        631L,
        11111L,        636L,        11211L,        674L,        11371L,        694L,        11720L,        749L,        13720L,
        750L,        13721L,        751L,        13722L,        752L,        13724L,        754L,        13782L,        760L,
        13783L,        765L,        18080L,        767L,        19888L,        808L,        19890L,        871L,        20011L,
        873L,        20012L,        901L,        22273L,        953L,        22289L,        992L,        22305L,        993L,
        22321L,        994L,        24554L,        995L,        25000L,        1080L,        25010L,        1109L,        26000L,
        1127L,        26208L,        1158L,        27017L,        1178L,        27374L,        1236L,        33434L,        1300L,
        50010L,        1313L,        50020L,        1433L,        50070L,        1434L,        50075L,        1494L,        50090L,
        1512L,        50091L,        1521L,        50100L,        1524L,        50105L,        1525L,        50470L,        1529L,
        50475L,        1645L,        60000L,        1646L,        60010L,        1649L,        60030L,        1701L,        60177L,
        1718L,        60179L,      0L,          5000L};
    private static final String[] DOMAIN_NAME = new String[] {"baidu.com", "qq.com", "eversec.com", "ddxz.org", "lnsy.edu",
            "casic.cn", "hb.gov.cn", "js.gov", "huawei.com", "xiaomi.cn", "oppo.xyz", "lenovo.us", "taobao.com", "alibaba.org",
            "github.com", "apache.org", "gitee.com"};

    private final DataMapper dataMapper;

    private final Random random = new Random(System.currentTimeMillis());

    private static final Logger LOGGER = LoggerFactory.getLogger(DataServiceImpl.class);

    public DataServiceImpl(BaseInfoMapper baseMapper, DataMapper dataMapper) {
        this.baseMapper = baseMapper;
        this.dataMapper = dataMapper;
    }
}
